DES加密算法原理及Python代码实现

您所在的位置:网站首页 秘钥和密钥 读音 DES加密算法原理及Python代码实现

DES加密算法原理及Python代码实现

2023-12-14 09:00| 来源: 网络整理| 查看: 265

写在前面:   1、本文中DES加解密基本流程及S盒等参数参照自杨波《现代密码学(第四版)》,实现过程均为自编函数。   2、为了说明64bit密钥中,只有56bit真正参与加解密过程,对网上代码中的密钥生成过程做出了修改,详见正文。   3、本文借鉴了网上部分代码,具体见参考文献,并对部分地方按题主想法进行了优化修改。

1. DES算法理论介绍

  具体可参见杨波《现代密码学(第四版)》。本文只做简要介绍。

1.1 DES介绍

  DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。

1.2 DES加解密算法描述 图 1.2 DES加密流程框图

  图1.2是DES加密变换框图,其中明文一组为64bit,密钥K长度56bit。加密过程有3个阶段:   1、初始置换IP,用于重排明文分组的64比特数据。   2、经过具有相同功能的16轮Feistel变换,每轮中F函数中都有置换和代换运算,第16轮变换的输出分为左右两半,并被交换次序。   3、经过一个逆初始置换IP-1(为IP的逆)从而产生64比特的密文。

1.2.1 轮结构

  采用Feistel相同的轮结构,将64bit的轮输入分为32bit的左、右两半,分别记为L和R: L i = R i − 1 L_i=R_{i-1} Li​=Ri−1​                 R i = L i − 1 ⊕ F ( R i − 1 , K i ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R_i=L_{i-1}\oplus F\left( R_{i-1},K_i \right)                Ri​=Li−1​⊕F(Ri−1​,Ki​)   其中,F函数示意图见图1.2.1。

图1.2.1 F函数示意图 1.2.2 密钥的生成 图 1.2.2 16轮密钥生成图

  图1.2.2是使用56比特密钥的方法。密钥首先通过一个置换函数PC_1,然后,对加密过程的每一轮,通过一个左循环移位和一个置换PC_2产生一个子密钥。其中每轮的置换都相同,但由于密钥被重复迭代,所以产生的每轮子密钥不相同。

1.2.3 DES解密

  和Feistel密码一样,DES的解密和加密使用同一种算法,但子密钥使用的顺序相反。

2. Python代码实现 2.1 实现思路

  由于加密与解密算法类似,此处给出加密算法实现思路:   Step1:从文件中读取明文;   Step2:将明文利用ASCII换成01比特流;   Step3:将明文比特流每64位分为一组,最后不足的用0补齐;   Step4:对64位比特加密操作(进行IP置换,16轮的Feistel变换、交换L、R、IP逆置换,将L、R合并为密文比特流);   Step5:将每一组密文比特流合并转换成密文字符保存至文件。

2.2 模块化程序设计 2.2.1 各个模块调用关系及实现功能设计 图2.2.1 各个模块调用关系及实现功能设计

  根据2.1中的实现思路,DES加解密算法各个模块调用关系及实现功能设计如图2.2.1所示,2.2.2中将详细介绍各个功能的代码实现。

2.2.2 模块功能实现

  针对2.2.1的实现思路,分析DES加解密算法流程,可将其具体分成不同的模块分别设计: 1.)文件读入模块

def read_file(filename): ''' filename : 打开文件名 return : 读取文件中字符串 ''' try: fp = open(filename,"r",encoding='utf-8') message = fp.read() fp.close() return message except: print("Open file error!")

2.)文件写入模块   将字符串写入文件text.txt与文件读入代码类似,只做如下修改:

fp = open('text.txt','w',encoding='utf-8') fp.write(message)

  def write_file(message): 输入需要写入字符串,即可生成含有该字符串的text.txt文件。

3.)字符串转01比特流

def str_bit( message ): ''' message :字符串 return :将读入的字符串序列转化成01比特流序列 ''' bits = "" for i in message: asc2i = bin(ord(i))[2:] #bin将十进制数转二进制返回带有0b的01字符串 '''为了统一每一个字符的01bit串位数相同,将每一个均补齐8位''' for j in range(8-len(asc2i)): asc2i = '0' + asc2i bits += asc2i return bits

  每一个字符利用ord( )函数转化成对应ASCII值,利用bin( )将其转换成二进制字符串。 4.)01比特流转字符   def bit_str(bits): 输入01比特串(长度要是8的倍数),返回对应的字符,核心代码如下,主要利用int( )和chr( )函数。

for i in range(len(bits)//8): temp += chr(int(bits[i*8:(i+1)*8],2))

5.)密钥字符串转比特流   本文假定密钥比特流的8、16、24、32、40、48、56、64位采用偶校验方式,分别校验其前面的7位01串。密钥字符串依然采用ASCII编码方式,一个字符占7位,第8位采用偶校验方式,核心代码如下:

def process_key(key): ''' key : 输入的密钥字符串 return : 64bit 01序列密钥(采用偶校验的方法) ''' key_bits = "" for i in key: count = 0 asc2i = bin(ord(i))[2:] '''将每一个ascii均补齐7位,第8位作为奇偶效验位''' for j in asc2i: count += int(j) if count % 2 == 0: asc2i += '0' else: asc2i += '1' for j in range(7-len(asc2i)): asc2i = '0' + asc2i key_bits += asc2i if len(key_bits) > 64: return key_bits[0:64] else: for i in range(64-len(key_bits)): key_bits += '0' return key_bits

6.)对比特流分组   函数定义如下,最后一组位数不足即补0。实现简单,此处不在赘述。

def divide(bits,bit): ''' bits : 将01bit按bit一组进行分组 return : 按bit位分组后得到的列表 '''

7.)IP置换   为了实现简单,提前将IP、IP_RE、PC_1、PC_2、E、P、S等盒值写入文件DES_BOX.py,主函数即可直接调用。IP置换实现如下:

def IP_change(bits): ''' bits:一组64位的01比特字符串 return:初始置换IP后64bit01序列 ''' ip_str = "" for i in IP: ip_str = ip_str + bits[i-1] return ip_str

8.)PC_1置换   实现代码同IP置换,此处不在赘述。 9.)比特串左移   def key_leftshift(key_str,num): 将输入的01比特流key_str循环左移num位返回,实现过于简单,此处不在赘述。 10.)PC_2置换   实现代码同IP置换,此处不在赘述。 11.)16轮密钥生成

def generate_key(key): ''' key : 64bit01密钥序列 return : 16轮的16个48bit01密钥列表按1-16顺序 ''' key_list = ["" for i in range(16)] key = PC_1_change(key) #1、调用置换PC_1 key_left = key[0:28] #2、左右28位分开 key_right = key[28:] for i in range(len(SHIFT)): #共16轮即16次左循环移位 key_left = key_leftshift(key_left, SHIFT[i]) #3、调用比特串左移函数 key_right = key_leftshift(key_right, SHIFT[i]) key_i = PC_2_change(key_left + key_right) #4、左右合并调用置换PC_2 key_list[i] = key_i #5、将每一轮的56bit密钥存入列表key_list return key_list

12.)E置换   实现代码同IP置换,此处不在赘述。 13.)异或运算   函数实现较为简单,将输入的两个字符串逐位运算即可,仅给出定义如下。

def xor(bits,ki): ''' bits : 48bit01字符串 / 32bit01 F函数输出 ki : 48bit01密钥序列 / 32bit01 Li return :bits与ki异或运算得到的48bit01 / 32bit01 '''

14.)单次S盒查找

def s(bits,i): ''' bits : 6 bit01字符串 i : 使用第i个s盒 return : 4 bit01字符串 ''' row = int(bits[0]+bits[5],2) col = int(bits[1:5],2) num = bin(S[i-1][row*16+col])[2:] #i-1号S盒的row*16+col号数 for i in range(4-len(num)): #补齐4位后输出 num = '0'+num return num

15.)S盒变换   def S_change(bits): 输入48bit字符串,输出经过S盒之后的32bit字符串。核心代码如下,调用8次单次S盒查找函数:

for i in range(8): temp = bits[i*6:(i+1)*6] temp = s(temp,i+1) s_change += temp

16.)P置换   实现代码同IP置换,此处不在赘述。 17.)F函数   通过调用12-16模块即可实现第 i i i轮F函数运算:

def F(bits,ki): ''' bits : 32bit 01 Ri输入 ki : 48bit 第i轮密钥 return : F函数输出32bit 01序列串 ''' bits = xor(E_change(bits),ki) bits = P_change(S_change(bits)) return bits

18.)IP逆置换   实现代码同IP置换,此处不在赘述。 19.)64bit加密   调用IP置换、16轮密钥生成、F函数、异或运算、IP逆置换等模块可以实现64bit一组明文的加密:

def des_encrypt(bits,key): ''' bits : 分组64bit 01明文字符串 key : 64bit01密钥 return : 加密得到64bit 01密文序列 ''' bits = IP_change(bits) # IP置换 L = bits[0:32] # 切片分成两个32bit R = bits[32:] key_list = generate_key(key) # 生成16个密钥 for i in range(16): # 16轮迭代变换 L_next = R R = xor(L,F(R,key_list[i])) L = L_next result = IP_RE_change( R + L) # IP逆置换 return result

20.)64bit解密   def des_decrypt(bits,key):该模块与64bit加密模块流程相同,不同在于16个密钥使用顺序相反,16轮代换代码如下,其余代码同加密。

for i in range(16): L_next = R R = xor(L,F(R,key_list[15-i])) L = L_next

21.)整体加密模块   def all_des_encrypt(message,key): 读入明文字符串message,以及密钥字符串key,返回加密后01比特流。通过调用字符串转01比特流、密钥字符串转比特流、对比特流分组、64bit加密等模块即可实现:

def all_des_encrypt(message,key): ''' message : 读入明文字符串 key : 读入密钥串 returns : 密文01序列 ''' message = str_bit(message) # 明文转01比特流 key = process_key(key) # 64bit初始密钥生成 mess_div = divide(message, 64) # 明文按64bit一组进行分组 result ="" for i in mess_div: result += des_encrypt(i, key) #对每一组进行加密运算 return result

22.)整体解密模块   def all_des_decrypt(message,key): 读入明文字符串message,以及密钥字符串key,返回解密后01比特流。与加密类似,此处不在赘述。

2.2.3 主模块

  输出提示语,并与用户交互。通过调用文件读入或写入、字符串转01比特流、比特流转01字符串、加解密等模块实现,伪代码如下:

2.3 Python源代码

  全部代码及相关注释点这里github。

2.4 关于密钥的说明

  起初按如下方式生成64bit密钥,即将密钥中每一个字符转成8bitASCII码,8个字符共构成64bit密钥。

def process_key(key): bin_key = str_bit(key) #调用字符串转01比特流模块 return bin_key

  结果发现“wuzhenll”和“vt{idomm”这两个密钥加密后的密文相同。   这是因为表面上这两个密码迥然不同,但是由于它们仅在奇偶校验位上有区别。例如,w的ASCII为01110111,v的ASCII为01110110,仅仅只在最后一位有区别。   由于64位密钥中的第8位、第16位、第24位、第32位、第40位、第48位、第56位、第64位作为奇偶校验位,在PC_1置换时去掉了这8位。如果输入的密码只是在这8位上有区别的话,那么操作后的结果也将是一样的。所以用这两个密码进行加密解密操作得到的结果是一样的。

2.5 使用说明

  运行环境: Python 3.7   使用方法: 将DES_BOX.py、DES.py、以及需要含有明密文的文本文件放置于同一目录下,运行DES.py程序,根据相应提示语即可完成操作。明文加密后乱码会自动保存到text.txt文件中。(注:输入的密钥将转化成对应的ASCII按照偶校验的方式构成64bit初始密钥)

2.6 结果测试

测试一:明文:keep early hours! 密钥:password

测试二: 明文:Have a good day! 密钥:messagee

参考文献

DES算法原理完整版

DES加解密python实现

DES算法中密钥的校验位



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3